import Header from '../../components/Header';
import ContentLayout from '../../components/ContentLayout';
import Title from '../../components/Title';
import titleList from '../../constants/titleList';
import './index.sass';

function Home() {
  return (
    <div className="page-wrap">
      <Header />
      <ContentLayout>
        <Title titleType="h1" id={titleList[0].nav}>
          {titleList[0].name}
        </Title>
        <Title titleType="h2">介绍</Title>
        <p>
          为了让程序有价值，我们需要能够处理最简单的数据单元：数字，字符串，结构体，布尔值等。
          TypeScript支持与JavaScript几乎相同的数据类型，此外还提供了实用的枚举类型方便我们使用。
        </p>
        <Title titleType="h2">布尔值</Title>
        <p>
          最基本的数据类型就是简单的true/false值，在JavaScript和TypeScript里叫做boolean（其它语言中也一样）。
        </p>
        <Title titleType="h2">数字</Title>
        <p>
          和JavaScript一样，TypeScript里的所有数字都是浮点数。 这些浮点数的类型是 number。
          除了支持十进制和十六进制字面量，TypeScript还支持ECMAScript
          2015中引入的二进制和八进制字面量。
        </p>
        <Title titleType="h2">字符串</Title>
        <p>
          JavaScript程序的另一项基本操作是处理网页或服务器端的文本数据。 像其它语言里一样，我们使用
          string表示文本数据类型。
          和JavaScript一样，可以使用双引号（&quot;）或单引号（&apos;）表示字符串。
        </p>
        <Title titleType="h2">数组</Title>
        <p>
          TypeScript像JavaScript一样可以操作数组元素。 有两种方式可以定义数组。
          第一种，可以在元素类型后面接上 []，表示由此类型元素组成的一个数组：
        </p>
        <p>第二种方式是使用数组泛型，Array&lt;元素类型&gt;</p>
        <Title titleType="h2">元组 Tuple</Title>
        <p>
          元组类型允许表示一个已知元素数量和类型的数组，各元素的类型不必相同。
          比如，你可以定义一对值分别为 string和number类型的元组。
        </p>
        <Title titleType="h2">枚举</Title>
        <p>
          enum类型是对JavaScript标准数据类型的一个补充。
          像C#等其它语言一样，使用枚举类型可以为一组数值赋予友好的名字。
        </p>
        <p>
          默认情况下，从0开始为元素编号。 你也可以手动的指定成员的数值。
          例如，我们将上面的例子改成从 1开始编号
        </p>
        <p>
          枚举类型提供的一个便利是你可以由枚举的值得到它的名字。
          例如，我们知道数值为2，但是不确定它映射到Color里的哪个名字，我们可以查找相应的名字
        </p>
        <Title titleType="h2">Any</Title>
        <p>
          有时候，我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。
          这些值可能来自于动态的内容，比如来自用户输入或第三方代码库。
          这种情况下，我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。
          那么我们可以使用 any类型来标记这些变量
        </p>
        <p>
          在对现有代码进行改写的时候，any类型是十分有用的，它允许你在编译时可选择地包含或移除类型检查。
          你可能认为 Object有相似的作用，就像它在其它语言中那样。 但是
          Object类型的变量只是允许你给它赋任意值 -
          但是却不能够在它上面调用任意的方法，即便它真的有这些方法
        </p>
        <Title titleType="h2">Void</Title>
        <p>
          某种程度上来说，void类型像是与any类型相反，它表示没有任何类型。
          当一个函数没有返回值时，你通常会见到其返回值类型是 void
        </p>
        <p>声明一个void类型的变量没有什么大用，因为你只能为它赋予undefined和null</p>
        <Title titleType="h2">Null 和 Undefined</Title>
        <p>
          TypeScript里，undefined和null两者各自有自己的类型分别叫做undefined和null。 和
          void相似，它们的本身的类型用处不是很大
        </p>
        <p>
          默认情况下null和undefined是所有类型的子类型。 就是说你可以把
          null和undefined赋值给number类型的变量。
        </p>
        <Title titleType="h2">Never</Title>
        <p>
          never类型表示的是那些永不存在的值的类型。例如，
          never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型；
          变量也可能是 never类型，当它们被永不为真的类型保护所约束时。
        </p>
        <p>
          never类型是任何类型的子类型，也可以赋值给任何类型；然而，没有类型是never的子类型或可以赋值给never类型（除了never本身之外）。
          即使 any也不可以赋值给never。
        </p>
        <Title titleType="h2">Object</Title>
        <p>
          object表示非原始类型，也就是除number，string，boolean，symbol，null或undefined之外的类型。
        </p>
        <Title titleType="h2">类型断言</Title>
        <p>
          有时候你会遇到这样的情况，你会比TypeScript更了解某个值的详细信息。
          通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型
        </p>
        <p>
          通过类型断言这种方式可以告诉编译器，“相信我，我知道自己在干什么”。
          类型断言好比其它语言里的类型转换，但是不进行特殊的数据检查和解构。
          它没有运行时的影响，只是在编译阶段起作用。
          TypeScript会假设你，程序员，已经进行了必须的检查。
        </p>
        <p>
          两种形式是等价的。
          至于使用哪个大多数情况下是凭个人喜好；然而，当你在TypeScript里使用JSX时，只有
          as语法断言是被允许的
        </p>
        <Title titleType="h2">关于let</Title>
        <p>
          你可能已经注意到了，我们使用let关键字来代替大家所熟悉的JavaScript关键字var。
          let关键字是JavaScript的一个新概念，TypeScript实现了它。
          我们会在以后详细介绍它，很多常见的问题都可以通过使用
          let来解决，所以尽可能地使用let来代替var吧。
        </p>
        <Title titleType="h1" id={titleList[1].nav}>
          {titleList[1].name}
        </Title>
        <Title titleType="h2">变量声明</Title>
        <p>
          let和const是JavaScript里相对较新的变量声明方式。 像我们之前提到过的，
          let在很多方面与var是相似的，但是可以帮助大家避免在JavaScript里常见一些问题。
          const是对let的一个增强，它能阻止对一个变量再次赋值。因为TypeScript是JavaScript的超集，所以它本身就支持let和const。
          下面我们会详细说明这些新的声明方式以及为什么推荐使用它们来代替
          var。如果你之前使用JavaScript时没有特别在意，那么这节内容会唤起你的回忆。 如果你已经对
          var声明的怪异之处了如指掌，那么你可以轻松地略过这节。
        </p>
        <Title titleType="h2">var 声明</Title>
        <Title titleType="h3">作用域规则</Title>
        <p>
          有些读者可能要多看几遍这个例子。 变量
          x是定义在*if语句里面*，但是我们却可以在语句的外面访问它。 这是因为
          var声明可以在包含它的函数，模块，命名空间或全局作用域内部任何位置被访问（我们后面会详细介绍），包含它的代码块对此没有什么影响。
          有些人称此为* var作用域或函数作用域*。
          函数参数也使用函数作用域。这些作用域规则可能会引发一些错误。
          其中之一就是，多次声明同一个变量并不会报错
        </p>
        <Title titleType="h3">块级作用域变量的获取</Title>
        <p>
          要小心使用解构。 从前面的例子可以看出，就算是最简单的解构表达式也是难以理解的。
          尤其当存在深层嵌套解构的时候，就算这时没有堆叠在一起的重命名，默认值和类型注解，也是令人难以理解的。
          解构表达式要尽量保持小而简单。 你自己也可以直接使用解构将会生成的赋值表达式。
        </p>
        <Title titleType="h1" id={titleList[2].nav}>
          {titleList[2].name}
        </Title>
        <Title titleType="h2">介绍</Title>
        <p>
          TypeScript的核心原则之一是对值所具有的结构进行类型检查。
          它有时被称做“鸭式辨型法”或“结构性子类型化”。
          在TypeScript里，接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。
        </p>
        <Title titleType="h2">接口初探</Title>
        <p>
          类型检查器会查看printLabel的调用。
          printLabel有一个参数，并要求这个对象参数有一个名为label类型为string的属性。
          需要注意的是，我们传入的对象参数实际上会包含很多属性，但是编译器只会检查那些必需的属性是否存在，并且其类型是否匹配。
          然而，有些时候TypeScript却并不会这么宽松，我们下面会稍做讲解。
        </p>
        <Title titleType="h2">可选属性</Title>
        <p>
          接口里的属性不全都是必需的。 有些是只在某些条件下存在，或者根本不存在。
          可选属性在应用“option bags”模式时很常用，即给函数传入的参数对象中只有部分属性赋值了。
        </p>
        <p>带有可选属性的接口与普通的接口定义差不多，只是在可选属性名字定义的后面加一个?符号。</p>
        <Title titleType="h2">只读属性</Title>
        <p>
          一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 readonly来指定只读属性
        </p>
        <p>
          TypeScript具有ReadonlyArray&lt;T&gt;类型，它与Array&lt;T&gt;相似，只是把所有可变方法去掉了，因此可以确保数组创建后再也不能被修改
        </p>
        <p>
          最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。
          做为变量使用的话用 const，若做为属性则使用readonly。
        </p>
        <Title titleType="h2">额外的属性检查</Title>
        <p>绕开这些检查非常简单。 最简便的方法是使用类型断言</p>
        <Title titleType="h2">函数类型</Title>
        <p>
          接口能够描述JavaScript中对象拥有的各种各样的外形。
          除了描述带有属性的普通对象外，接口也可以描述函数类型。
        </p>
        <p>
          为了使用接口表示函数类型，我们需要给接口定义一个调用签名。
          它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。
        </p>
        <p>对于函数类型的类型检查来说，函数的参数名不需要与接口里定义的名字相匹配。</p>
        <Title titleType="h2">可索引的类型</Title>
        <p>
          与使用接口描述函数类型差不多，我们也可以描述那些能够“通过索引得到”的类型，比如a[10]或ageMap[&lt;daniel&gt;]。
          可索引类型具有一个 索引签名，它描述了对象索引的类型，还有相应的索引返回值类型。
        </p>
        <Title titleType="h2">类类型</Title>
        <Title titleType="h3">实现接口</Title>
        <p>
          与C#或Java里接口的基本作用一样，TypeScript也能够用它来明确的强制一个类去符合某种契约。
        </p>
        <Title titleType="h2">继承接口</Title>
        <p>
          和类一样，接口也可以相互继承。
          这让我们能够从一个接口里复制成员到另一个接口里，可以更灵活地将接口分割到可重用的模块里。
        </p>
        <p>一个接口可以继承多个接口，创建出多个接口的合成接口。</p>
        <Title titleType="h2">混合类型</Title>
        <p>
          先前我们提过，接口能够描述JavaScript里丰富的类型。
          因为JavaScript其动态灵活的特点，有时你会希望一个对象可以同时具有上面提到的多种类型。
        </p>
        <Title titleType="h2">接口继承类</Title>
        <p>
          当接口继承了一个类类型时，它会继承类的成员但不包括其实现。
          就好像接口声明了所有类中存在的成员，但并没有提供具体实现一样。
          接口同样会继承到类的private和protected成员。
          这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时，这个接口类型只能被这个类或其子类所实现（implement）。当你有一个庞大的继承结构时这很有用，但要指出的是你的代码只在子类拥有特定属性时起作用。
          这个子类除了继承至基类外与基类没有任何关系。
        </p>
        <Title titleType="h1" id={titleList[3].nav}>
          {titleList[3].name}
        </Title>
        <Title titleType="h2">介绍</Title>
        <p>
          传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件，但对于熟悉使用面向对象方式的程序员来讲就有些棘手，因为他们用的是基于类的继承并且对象是由类构建出来的。
          从ECMAScript 2015，也就是ECMAScript
          6开始，JavaScript程序员将能够使用基于类的面向对象的方式。
          使用TypeScript，我们允许开发者现在就使用这些特性，并且编译后的JavaScript可以在所有主流浏览器和平台上运行，而不需要等到下个JavaScript版本。
        </p>
        <Title titleType="h2">类</Title>
        <p>
          我们使用 new构造了 Greeter类的一个实例。 它会调用之前定义的构造函数，创建一个
          Greeter类型的新对象，并执行构造函数初始化它。
        </p>
        <Title titleType="h2">继承</Title>
        <p>
          在TypeScript里，我们可以使用常用的面向对象模式。
          基于类的程序设计中一种最基本的模式是允许使用继承来扩展现有的类。
        </p>
        <p>
          派生类包含了一个构造函数，它 必须调用 super()，它会执行基类的构造函数。
          而且，在构造函数里访问 this的属性之前，我们 一定要调用 super()。
          这个是TypeScript强制执行的一条重要规则。
        </p>
        <Title titleType="h2">公共，私有与受保护的修饰符</Title>
        <Title titleType="h3">默认为 public</Title>
        <p>
          在上面的例子里，我们可以自由的访问程序里定义的成员。
          如果你对其它语言中的类比较了解，就会注意到我们在之前的代码里并没有使用
          public来做修饰；例如，C#要求必须明确地使用 public指定成员是可见的。
          在TypeScript里，成员都默认为 public。
        </p>
        <Title titleType="h3">理解 private</Title>
        <p>当成员被标记成 private时，它就不能在声明它的类的外部访问。</p>
        <Title titleType="h3">理解 protected</Title>
        <p>
          protected修饰符与 private修饰符的行为很相似，但有一点不同，
          protected成员在派生类中仍然可以访问
        </p>
        <p>
          构造函数也可以被标记成 protected。 这意味着这个类不能在包含它的类外被实例化，但是能被继承
        </p>
        <Title titleType="h3">readonly修饰符</Title>
        <p>
          你可以使用 readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。
        </p>
        <Title titleType="h2">存取器</Title>
        <p>
          TypeScript支持通过getters/setters来截取对对象成员的访问。
          它能帮助你有效的控制对对象成员的访问。
        </p>
        <p>对于存取器有下面几点需要注意的：</p>
        <p>
          首先，存取器要求你将编译器设置为输出ECMAScript 5或更高。 不支持降级到ECMAScript 3。
          其次，只带有 get不带有 set的存取器自动被推断为 readonly。 这在从代码生成
          .d.ts文件时是有帮助的，因为利用这个属性的用户会看到不允许够改变它的值。
        </p>
        <Title titleType="h2">静态属性</Title>
        <p>
          到目前为止，我们只讨论了类的实例成员，那些仅当类被实例化的时候才会被初始化的属性。
          我们也可以创建类的静态成员，这些属性存在于类本身上面而不是类的实例上。
        </p>
        <Title titleType="h2">抽象类</Title>
        <p>
          抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。
          不同于接口，抽象类可以包含成员的实现细节。
          abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法。
        </p>
        <Title titleType="h2">高级技巧</Title>
        <Title titleType="h3">构造函数</Title>
        <p>
          当你在TypeScript里声明了一个类的时候，实际上同时声明了很多东西。 首先就是类的 实例的类型。
        </p>
        <Title titleType="h3">把类当做接口使用</Title>
        <p>
          类定义会创建两个东西：类的实例类型和一个构造函数。
          因为类可以创建出类型，所以你能够在允许使用接口的地方使用类。
        </p>
        <Title titleType="h1" id={titleList[4].nav}>
          {titleList[4].name}
        </Title>
        <Title titleType="h2">介绍</Title>
        <p>
          函数是JavaScript应用程序的基础。 它帮助你实现抽象层，模拟类，信息隐藏和模块。
          在TypeScript里，虽然已经支持类，命名空间和模块，但函数仍然是主要的定义 行为的地方。
          TypeScript为JavaScript函数添加了额外的功能，让我们可以更容易地使用。
        </p>
        <Title titleType="h2">函数</Title>
        <p>
          和JavaScript一样，TypeScript函数可以创建有名字的函数和匿名函数。
          你可以随意选择适合应用程序的方式，不论是定义一系列API函数还是只使用一次的函数。
        </p>
        <p>通过下面的例子可以迅速回想起这两种JavaScript中的函数：</p>
        <pre>
          function add(x, y) {`return x + y`}
          <br />
          <br />
          let myAdd = function(x, y) {`return x + y`};
        </pre>
        <p>
          在JavaScript里，函数可以使用函数体外部的变量。 当函数这么做时，我们说它‘捕获’了这些变量。
          至于为什么可以这样做以及其中的利弊超出了本文的范围，但是深刻理解这个机制对学习JavaScript和TypeScript会很有帮助。
        </p>
        <pre>
          let z = 100;
          <br />
          <br />
          function addToZ(x, y) {`return x + z + y`}
        </pre>
        <Title titleType="h2">函数类型</Title>
        <Title titleType="h3">为函数定义类型</Title>
        <pre>
          function add(x: number, y: number): number {`return x + y`}
          <br />
          <br />
          let myAdd = function(x: number, y: number): number {`return x + y`}
        </pre>
        <p>
          我们可以给每个参数添加类型之后再为函数本身添加返回值类型。
          TypeScript能够根据返回语句自动推断出返回值类型，因此我们通常省略它。
        </p>
        <Title titleType="h3">书写完整函数类型</Title>
        <p>现在我们已经为函数指定了类型，下面让我们写出函数的完整类型。</p>
        <p>
          函数类型包含两部分：参数类型和返回值类型。 当写出完整函数类型的时候，这两部分都是需要的。
          我们以参数列表的形式写出参数类型，为每个参数指定一个名字和类型。
          这个名字只是为了增加可读性。 我们也可以这么写：
        </p>
        <p>只要参数类型是匹配的，那么就认为它是有效的函数类型，而不在乎参数名是否正确。</p>
        <p>
          第二部分是返回值类型。 对于返回值，我们在函数和返回值类型之前使用(
          =&gt;)符号，使之清晰明了。
          如之前提到的，返回值类型是函数类型的必要部分，如果函数没有返回任何值，你也必须指定返回值类型为
          void而不能留空。
        </p>
        <p>
          函数的类型只是由参数类型和返回值组成的。 函数中使用的捕获变量不会体现在类型里。
          实际上，这些变量是函数的隐藏状态并不是组成API的一部分。
        </p>
        <Title titleType="h3">推断类型</Title>
        <p>在赋值语句的一边指定了类型但是另一边没有类型的话，TypeScript编译器会自动识别出类型：</p>
        <p>这叫做“按上下文归类”，是类型推论的一种。 它帮助我们更好地为程序指定类型。</p>
        <Title titleType="h2">可选参数和默认参数</Title>
        <p>
          TypeScript里的每个函数参数都是必须的。 这不是指不能传递
          null或undefined作为参数，而是说编译器检查用户是否为每个参数都传入了值。
          编译器还会假设只有这些参数会被传递进函数。
          简短地说，传递给一个函数的参数个数必须与函数期望的参数个数一致。
        </p>
        <p>
          JavaScript里，每个参数都是可选的，可传可不传。 没传参的时候，它的值就是undefined。
          在TypeScript里我们可以在参数名旁使用 ?实现可选参数的功能。 比如，我们想让last
          name是可选的：
        </p>
        <p>
          可选参数必须跟在必须参数后面。 如果上例我们想让first
          name是可选的，那么就必须调整它们的位置，把first name放在后面。
        </p>
        <p>
          在TypeScript里，我们也可以为参数提供一个默认值当用户没有传递这个参数或传递的值是undefined时。
          它们叫做有默认初始化值的参数。 让我们修改上例，把last
          name的默认值设置为&ldquo;Smith&ldquo;。
        </p>
        <p>
          在所有必须参数后面的带默认初始化的参数都是可选的，与可选参数一样，在调用函数的时候可以省略。
          也就是说可选参数与末尾的默认参数共享参数类型。
        </p>
        <p>
          与普通可选参数不同的是，带默认值的参数不需要放在必须参数的后面。
          如果带默认值的参数出现在必须参数前面，用户必须明确的传入 undefined值来获得默认值。
          例如，我们重写最后一个例子，让 firstName是带默认值的参数：
        </p>
        <Title titleType="h2">剩余参数</Title>
        <p>
          必要参数，默认参数和可选参数有个共同点：它们表示某一个参数。
          有时，你想同时操作多个参数，或者你并不知道会有多少参数传递进来。
          在JavaScript里，你可以使用 arguments来访问所有传入的参数。
        </p>
        <p>在TypeScript里，你可以把所有参数收集到一个变量里：</p>
        <p>
          剩余参数会被当做个数不限的可选参数。 可以一个都没有，同样也可以有任意个。
          编译器创建参数数组，名字是你在省略号（ ...）后面给定的名字，你可以在函数体内使用这个数组。
        </p>
        <p>这个省略号也会在带有剩余参数的函数类型定义上使用到：</p>
        <Title titleType="h2">this</Title>
        <p>
          TypeScript能通知你错误地使用了 this的地方。 如果你想了解JavaScript里的
          this是如何工作的，那么首先阅读Yehuda Katz写的Understanding JavaScript Function Invocation
          and &ldquo;this&ldquo;。 Yehuda的文章详细的阐述了
          this的内部工作原理，因此我们这里只做简单介绍。
        </p>
        <Title titleType="h3">this和箭头函数</Title>
        <p>
          JavaScript里，this的值在函数被调用的时候才会指定。
          这是个既强大又灵活的特点，但是你需要花点时间弄清楚函数调用的上下文是什么。
          但众所周知，这不是一件很简单的事，尤其是在返回一个函数或将函数当做参数传递的时候。
        </p>
        <Title titleType="h3">重载</Title>
        <p>
          JavaScript本身是个动态语言。
          JavaScript里函数根据传入不同的参数而返回不同类型的数据是很常见的。
        </p>
        <Title titleType="h1" id={titleList[5].nav}>
          {titleList[5].name}
        </Title>
        <Title titleType="h2">介绍</Title>
        <p>
          软件工程中，我们不仅要创建一致的定义良好的API，同时也要考虑可重用性。
          组件不仅能够支持当前的数据类型，同时也能支持未来的数据类型，这在创建大型系统时为你提供了十分灵活的功能。
        </p>
        <p>
          在像C#和Java这样的语言中，可以使用泛型来创建可重用的组件，一个组件可以支持多种类型的数据。
          这样用户就可以以自己的数据类型来使用组件。
        </p>
        <Title titleType="h2">泛型之Hello World</Title>
        <p>
          我们给identity添加了类型变量T。
          T帮助我们捕获用户传入的类型（比如：number），之后我们就可以使用这个类型。
          之后我们再次使用了 T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。
          这允许我们跟踪函数里使用的类型的信息。
        </p>
        <p>
          我们把这个版本的identity函数叫做泛型，因为它可以适用于多个类型。 不同于使用
          any，它不会丢失信息，像第一个例子那像保持准确性，传入数值类型并返回数值类型。
        </p>
        <p>我们定义了泛型函数后，可以用两种方法使用。 第一种是，传入所有的参数，包含类型参数</p>
        <p>
          这里我们明确的指定了T是string类型，并做为一个参数传给函数，使用了&lg;&gt;括起来而不是().
        </p>
        <p>第二种方法更普遍。利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型</p>
        <p>
          注意我们没必要使用尖括号（&lg;&gt;）来明确地传入类型；编译器可以查看myString的值，然后把T设置为它的类型。
          类型推论帮助我们保持代码精简和高可读性。如果编译器不能够自动地推断出类型的话，只能像上面那样明确的传入T的类型，在一些复杂的情况下，这是可能出现的。
        </p>
        <Title titleType="h2">使用泛型变量</Title>
        <p>
          使用泛型创建像identity这样的泛型函数时，编译器要求你在函数体必须正确的使用这个通用的类型。
          换句话说，你必须把这些参数当做是任意或所有类型.
        </p>
        <Title titleType="h2">泛型类型</Title>
        <p>
          上一节，我们创建了identity通用函数，可以适用于不同的类型。
          在这节，我们研究一下函数本身的类型，以及如何创建泛型接口。
        </p>
        <p>
          泛型函数的类型与非泛型函数的类型没什么不同，只是有一个类型参数在最前面，像函数声明一样
        </p>
        <p>这引导我们去写第一个泛型接口了。 我们把上面例子里的对象字面量拿出来做为一个接口</p>
        <p>
          一个相似的例子，我们可能想把泛型参数当作整个接口的一个参数。
          这样我们就能清楚的知道使用的具体是哪个泛型类型（比如：
          Dictionary&lt;string&gt;而不只是Dictionary）。
          这样接口里的其它成员也能知道这个参数的类型了。
        </p>
        <p>
          注意，我们的示例做了少许改动。 不再描述泛型函数，而是把非泛型函数签名作为泛型类型一部分。
          当我们使用
          GenericIdentityFn的时候，还得传入一个类型参数来指定泛型类型（这里是：number），锁定了之后代码里使用的类型。
          对于描述哪部分类型属于泛型部分来说，理解何时把参数放在调用签名里和何时放在接口上是很有帮助的。
        </p>
        <p>除了泛型接口，我们还可以创建泛型类。 注意，无法创建泛型枚举和泛型命名空间</p>
        <Title titleType="h2">泛型类</Title>
        <p>泛型类看上去与泛型接口差不多。 泛型类使用（&lt;&gt;）括起泛型类型，跟在类名后面。</p>
        <p>
          我们在类那节说过，类有两部分：静态部分和实例部分。
          泛型类指的是实例部分的类型，所以类的静态属性不能使用这个泛型类型。
        </p>
        <Title titleType="h2">泛型约束</Title>
        <p>
          你应该会记得之前的一个例子，我们有时候想操作某类型的一组值，并且我们知道这组值具有什么样的属性。
          在
          loggingIdentity例子中，我们想访问arg的length属性，但是编译器并不能证明每种类型都有length属性，所以就报错了。
        </p>
        <p>
          相比于操作any所有类型，我们想要限制函数去处理任意带有.length属性的所有类型。
          只要传入的类型有这个属性，我们就允许，就是说至少包含这一属性。
          为此，我们需要列出对于T的约束要求。
        </p>
        <p>
          为此，我们定义一个接口来描述约束条件。 创建一个包含
          .length属性的接口，使用这个接口和extends关键字来实现约束
        </p>
        <Title titleType="h2">在泛型约束中使用类型参数</Title>
        <p>
          你可以声明一个类型参数，且它被另一个类型参数所约束。
          比如，现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象
          obj上，因此我们需要在这两个类型之间使用约束。
        </p>
        <Title titleType="h2">在泛型里使用类类型</Title>
        <p>在TypeScript使用泛型创建工厂函数时，需要引用构造函数的类类型。</p>
        <Title titleType="h1" id={titleList[6].nav}>
          {titleList[6].name}
        </Title>
        <Title titleType="h2">枚举</Title>
        <Title titleType="h3">枚举</Title>
        <p>
          使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。
          TypeScript支持数字的和基于字符串的枚举。
        </p>
        <Title titleType="h3">数字枚举</Title>
        <p>使用枚举很简单：通过枚举的属性来访问枚举成员，和枚举的名字来访问枚举类型</p>
        <Title titleType="h3">字符串枚举</Title>
        <p>
          字符串枚举的概念很简单，但是有细微的 运行时的差别。
          在一个字符串枚举里，每个成员都必须用字符串字面量，或另外一个字符串枚举成员进行初始化。
        </p>
        <p>
          由于字符串枚举没有自增长的行为，字符串枚举可以很好的序列化。
          换句话说，如果你正在调试并且必须要读一个数字枚举的运行时的值，这个值通常是很难读的 -
          它并不能表达有用的信息（尽管
          反向映射会有所帮助），字符串枚举允许你提供一个运行时有意义的并且可读的值，独立于枚举成员的名字。
        </p>
        <Title titleType="h3">异构枚举（Heterogeneous enums）</Title>
        <p>从技术的角度来说，枚举可以混合字符串和数字成员，但是似乎你并不会这么做</p>
        <p>除非你真的想要利用JavaScript运行时的行为，否则我们不建议这样做。</p>
        <Title titleType="h3">计算的和常量成员</Title>
        <p>
          每个枚举成员都带有一个值，它可以是 常量或 计算出来的。
          当满足如下条件时，枚举成员被当作是常量
        </p>
        <p>
          枚举成员使用 常量枚举表达式初始化。
          常数枚举表达式是TypeScript表达式的子集，它可以在编译阶段求值。
          当一个表达式满足下面条件之一时，它就是一个常量枚举表达式
        </p>
        <p>1. 一个枚举表达式字面量（主要是字符串字面量或数字字面量）</p>
        <p>2. 一个对之前定义的常量枚举成员的引用（可以是在不同的枚举类型中定义的）</p>
        <p>3. 带括号的常量枚举表达式</p>
        <p>4. 一元运算符 +, -, ~其中之一应用在了常量枚举表达式</p>
        <p>
          5. 常量枚举表达式做为二元运算符 +, -, *, /, %, &lt;&lt;, &gt;&gt;, &gt;&gt;&gt;, &, |,
          ^的操作对象。 若常数枚举表达式求值后为 NaN或 Infinity，则会在编译阶段报错。
        </p>
        <p>所有其它情况的枚举成员被当作是需要计算得出的值。</p>
        <Title titleType="h3">联合枚举与枚举成员的类型</Title>
        <p>
          存在一种特殊的非计算的常量枚举成员的子集：字面量枚举成员。
          字面量枚举成员是指不带有初始值的常量枚举成员，或者是值被初始化为
        </p>
        <p>任何字符串字面量（例如： &quot;foo&quot;， &quot;bar&quot;， &quot;baz&quot;）</p>
        <p>任何数字字面量（例如： 1, 100</p>
        <p>应用了一元 -符号的数字字面量（例如： -1, -100</p>
        <p>当所有枚举成员都拥有字面量枚举值时，它就带有了一种特殊的语义。</p>
        <p>首先，枚举成员成为了类型！ 例如，我们可以说某些成员 只能是枚举成员的值</p>
        <p>
          另一个变化是枚举类型本身变成了每个枚举成员的 联合。
          虽然我们还没有讨论[联合类型](./Advanced
          Types.md#union-types)，但你只要知道通过联合枚举，类型系统能够利用这样一个事实，它可以知道枚举里的值的集合。
          因此，TypeScript能够捕获在比较值的时候犯的愚蠢的错误。
        </p>
        <Title titleType="h3">运行时的枚举</Title>
        <p>枚举是在运行时真正存在的对象。</p>
        <Title titleType="h3">反向映射</Title>
        <p>
          除了创建一个以属性名做为对象成员的对象之外，数字枚举成员还具有了
          反向映射，从枚举值到枚举名字。
        </p>
        <p>要注意的是 不会为字符串枚举成员生成反向映射。</p>
        <Title titleType="h3">const枚举</Title>
        <p>
          大多数情况下，枚举是十分有效的方案。 然而在某些情况下需求很严格。
          为了避免在额外生成的代码上的开销和额外的非直接的对枚举成员的访问，我们可以使用 const枚举。
          常量枚举通过在枚举上使用 const修饰符来定义。
        </p>
        <p>
          常量枚举只能使用常量枚举表达式，并且不同于常规的枚举，它们在编译阶段会被删除。
          常量枚举成员在使用的地方会被内联进来。
          之所以可以这么做是因为，常量枚举不允许包含计算成员。
        </p>
        <Title titleType="h2">外部枚举</Title>
        <p>外部枚举用来描述已经存在的枚举类型的形状。</p>
        <p>
          外部枚举和非外部枚举之间有一个重要的区别，在正常的枚举里，没有初始化方法的成员被当成常数成员。
          对于非常数的外部枚举而言，没有初始化方法时被当做需要经过计算的。
        </p>
        <Title titleType="h1" id={titleList[7].nav}>
          {titleList[7].name}
        </Title>
        <Title titleType="h2">基础</Title>
        <p>Ts里面，在有些没有明确指出类型的地方，类型推论会帮助提供类型。</p>
        <Title titleType="h2">最佳通用类型</Title>
        <p>
          当需要从几个表达式中推断类型的时候，会使用这些表达式的类型来推断出一个最合适的通用类型。
        </p>
        <p>
          我们想让zoo被推断为Animal[]类型，但是这个数组里面没有对象是Animal类型的，因此不能推断出这个结果。为了更正，当候选类型不能使用的时候我们需要明确的指出类型：
        </p>
        <Title titleType="h2">上下文类型</Title>
        <p>
          TS
          类型推论也可能按照相反的方向进行。这被叫做“按上下文归类”。按上下文归类会发生在表达式的类型与所处的位置相关。
        </p>
        <Title titleType="h1" id={titleList[8].nav}>
          {titleList[8].name}
        </Title>
        <Title titleType="h3">介绍</Title>
        <p>
          TS
          里的类型兼容性是基于结构子类型的。结构类型是一种只使用其成员来描述类型的方式。它正好与名义（nominal）类型形成对比。（译者注：在基于名义类型的类型系统中，数据类型的兼容性或等价性是通过明确的声明和／或类型的名称来决定的。这与结构性类型系统不同，它是基于类型的组成结构，且不要求明确地声明。）
        </p>
        <Title titleType="h3">关于可靠性的注意事项</Title>
        <p>
          TypeScript的类型系统允许某些在编译阶段无法确认其安全性的操作。当一个类型系统具此属性时，被当做是“不可靠”的。TypeScript允许这种不可靠行为的发生是经过仔细考虑的。通过这篇文章，我们会解释什么时候会发生这种情况和其有利的一面。
        </p>
        <Title titleType="h3">开始</Title>
        <p>TypeScript结构化类型系统的基本规则是，如果x要兼容y，那么y至少具有与x相同的属性。</p>
        <p>
          要查看x是否能赋值给y，首先看它们的参数列表。 x的每个参数必须能在y里找到对应类型的参数。
          注意的是参数的名字相同与否无所谓，
        </p>
        <p>类型系统强制源函数的返回值类型必须是目标函数返回值类型的子类型。</p>
        <Title titleType="h3">函数参数双向协变</Title>
        <p>
          当比较函数参数类型时，只有当源函数参数能够赋值给目标函数或者反过来时才能赋值成功。
          这是不稳定的，因为调用者可能传入了一个具有更精确类型信息的函数，但是调用这个传入的函数的时候却使用了不是那么精确的类型信息。
          实际上，这极少会发生错误，并且能够实现很多JavaScript里的常见模式。
        </p>
        <Title titleType="h3">函数重载</Title>
        <p>
          对于有重载的函数，源函数的每个重载都要在目标函数上找到对应的函数签名。
          这确保了目标函数可以在所有源函数可调用的地方调用。
        </p>
        <Title titleType="h3">枚举</Title>
        <p>枚举类型与数字类型兼容，并且数字类型与枚举类型兼容。不同枚举类型之间是不兼容的。</p>
        <Title titleType="h3">类</Title>
        <p>
          类与对象字面量和接口差不多，但有一点不同：类有静态部分和实例部分的类型。
          比较两个类类型的对象时，只有实例的成员会被比较。 静态成员和构造函数不在比较的范围内。
        </p>
        <Title titleType="h3">类的私有成员和受保护成员</Title>
        <p>
          类的私有成员和受保护成员会影响兼容性。
          当检查类实例的兼容时，如果目标类型包含一个私有成员，那么源类型必须包含来自同一个类的这个私有成员。
          同样地，这条规则也适用于包含受保护成员实例的类型检查。
          这允许子类赋值给父类，但是不能赋值给其它有同样类型的类。
        </p>
        <Title titleType="h3">泛型</Title>
        <p>
          因为TypeScript是<b>结构性的类型系统</b>，类型参数只影响使用其做为类型一部分的结果类型。
        </p>
        <Title titleType="h2">高级主题</Title>
        <Title titleType="h3">子类型与赋值</Title>
        <p>
          目前为止，我们使用了“兼容性”，它在语言规范里没有定义。
          在TypeScript里，有两种兼容性：子类型和赋值。
          它们的不同点在于，赋值扩展了子类型兼容性，增加了一些规则，允许和any来回赋值，以及enum和对应数字值之间的来回赋值。
        </p>
        <p>
          语言里的不同地方分别使用了它们之中的机制。
          实际上，类型兼容性是由赋值兼容性来控制的，即使在implements和extends语句也不例外。
        </p>
        <Title titleType="h1" id={titleList[9].nav}>
          {titleList[9].name}
        </Title>
        <Title titleType="h2">交叉类型</Title>
        <p>
          交叉类型是将多个类型合并为一个类型。
          这让我们可以把现有的多种类型叠加到一起成为一种类型，它包含了所需的所有类型的特性。
        </p>
        <p>我们大多是在混入（mixins）或其它不适合典型面向对象模型的地方看到交叉类型的使用。</p>
        <Title titleType="h2">联合类型</Title>
        <p>
          联合类型与交叉类型很有关联，但是使用上却完全不同。
          偶尔你会遇到这种情况，一个代码库希望传入 number或 string类型的参数。
        </p>
        <p>
          联合类型表示一个值可以是几种类型之一。 我们用竖线（ |）分隔每个类型，所以 number | string
          | boolean表示一个值可以是 number， string，或 boolean。
        </p>
        <Title titleType="h2">类型保护与区分类型</Title>
        <p>
          联合类型适合于那些值可以为不同类型的情况。 但当我们想确切地了解是否为 Fish时怎么办？
          JavaScript里常用来区分2个可能值的方法是检查成员是否存在。
          如之前提及的，我们只能访问联合类型中共同拥有的成员。
        </p>
        <Title titleType="h3">用户自定义的类型保护</Title>
        <p>
          TypeScript里的 类型保护机制让它成为了现实。
          类型保护就是一些表达式，它们会在运行时检查以确保在某个作用域里的类型。
          要定义一个类型保护，我们只要简单地定义一个函数，它的返回值是一个 类型谓词：
        </p>
        <Title titleType="h3">typeof类型保护</Title>
        <p>
          这些* typeof类型保护*只有两种形式能被识别： typeof v === "typename"和 typeof v !==
          "typename"， "typename"必须是 "number"， "string"， "boolean"或 "symbol"。
          但是TypeScript并不会阻止你与其它字符串比较，语言不会把那些表达式识别为类型保护。
        </p>
        <Title titleType="h3">instanceof类型保护</Title>
        <p>instanceof类型保护是通过构造函数来细化类型的一种方式。</p>
        <Title titleType="h2">可以为null的类型</Title>
        <Title titleType="h2">可选参数和属性</Title>
        <Title titleType="h2">类型保护和类型断言</Title>
        <p>
          由于可以为null的类型是通过联合类型实现，那么你需要使用类型保护来去除 null。
          幸运地是这与在JavaScript里写的代码一致：
        </p>
        <Title titleType="h2">类型别名</Title>
        <p>
          类型别名会给一个类型起个新名字。
          类型别名有时和接口很像，但是可以作用于原始值，联合类型，元组以及其它任何你需要手写的类型。
        </p>
        <p>同接口一样，类型别名也可以是泛型 - 我们可以添加类型参数并且在别名声明的右侧传入</p>
        <p>然而，类型别名不能出现在声明右侧的任何地方。</p>
        <p>
          <b>软件中的对象应该对于扩展是开放的，但是对于修改是封闭的，</b>
          你应该尽量去使用接口代替类型别名
        </p>
        <p>
          如果你无法通过接口来描述一个类型并且需要使用联合类型或元组类型，这时通常会使用类型别名。
        </p>
        <Title titleType="h2">字符串字面量类型</Title>
        <p>
          字符串字面量类型允许你指定字符串必须的固定值。
          在实际应用中，字符串字面量类型可以与联合类型，类型保护和类型别名很好的配合。
          通过结合使用这些特性，你可以实现类似枚举类型的字符串。
        </p>
        <Title titleType="h2">数字字面量类型</Title>
        <Title titleType="h2">枚举成员类型</Title>
        <Title titleType="h2">可辨识联合</Title>
        <Title titleType="h3">完整性检查</Title>
        <Title titleType="h2">多态的 this类型</Title>
        <Title titleType="h2">索引类型</Title>
        <p>
          使用索引类型，编译器就能够检查使用了动态属性名的代码。
          例如，一个常见的JavaScript模式是从对象中选取属性的子集。
        </p>
        <Title titleType="h2">映射类型</Title>
        <p>这在JavaScript里经常出现，TypeScript提供了从旧类型中创建新类型的一种方式 — 映射类型。</p>
        <Title titleType="h1" id={titleList[10].nav}>
          {titleList[10].name}
        </Title>
        <Title titleType="h2">介绍</Title>
        <p>symbol类型的值是通过Symbol构造函数创建的。</p>
        <Title titleType="h1" id={titleList[11].nav}>
          {titleList[11].name}
        </Title>
        <Title titleType="h2">可迭代性</Title>
        <p>当目标为兼容ECMAScipt 2015的引擎时，编译器会生成相应引擎的for..of内置迭代器实现方式。</p>
        <Title titleType="h1" id={titleList[12].nav}>
          {titleList[12].name}
        </Title>
        <p>
          关于术语的一点说明: 请务必注意一点，TypeScript 1.5里术语名已经发生了变化。
          “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”，这是为了与 ECMAScript
          2015里的术语保持一致，(也就是说 module X 相当于现在推荐的写法 namespace X )。
        </p>
        <Title titleType="h2">介绍</Title>
        <p>从ECMAScript 2015开始，JavaScript引入了模块的概念。TypeScript也沿用这个概念.</p>

        <p>
          模块在其自身的作用域里执行，而不是在全局作用域里；这意味着定义在一个模块里的变量，函数，类等等在模块外部是不可见的，除非你明确地使用export形式之一导出它们。
          相反，如果想使用其它模块导出的变量，函数，类，接口等的时候，你必须要导入它们，可以使用
          import形式之一。
        </p>
        <p>模块是自声明的；两个模块之间的关系是通过在文件级别上使用imports和exports建立的。</p>
        <p>
          模块使用模块加载器去导入其它的模块。
          在运行时，模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。
          大家最熟知的JavaScript模块加载器是服务于Node.js的 CommonJS和服务于Web应用的Require.js。
        </p>
        <p>
          TypeScript与ECMAScript
          2015一样，任何包含顶级import或者export的文件都被当成一个模块。相反地，如果一个文件不带有顶级的import或者export声明，那么它的内容被视为全局可见的（因此对模块也是可见的）。
        </p>
        <Title titleType="h2">导出</Title>
        <Title titleType="h3">导出声明</Title>
        <p>任何声明（比如变量，函数，类，类型别名或接口）都能够通过添加export关键字来导出。</p>
        <Title titleType="h3">导出语句</Title>
        <p>导出语句很便利，因为我们可能需要对导出的部分重命名，</p>
        <Title titleType="h3">重新导出</Title>
        <p>
          我们经常会去扩展其它模块，并且只导出那个模块的部分内容。
          重新导出功能并不会在当前模块导入那个模块或定义一个新的局部变量。
        </p>
        <Title titleType="h2">导入</Title>
        <p>
          模块的导入操作与导出一样简单。 可以使用以下 import形式之一来导入其它模块中的导出内容。
        </p>
        <Title titleType="h3">导入一个模块中的某个导出内容</Title>
        <p>可以对导入内容重命名: ZipCodeValidator as ZCV</p>
        <Title titleType="h3">将整个模块导入到一个变量，并通过它来访问模块的导出部分</Title>
        <p>import * as validator</p>
        <Title titleType="h3">具有副作用的导入模块</Title>
        <p>
          尽管不推荐这么做，一些模块会设置一些全局状态供其它模块使用。
          这些模块可能没有任何的导出或用户根本就不关注它的导出。 使用下面的方法来导入这类模块：
        </p>
        <p>import "./my-module.js";</p>
        <Title titleType="h2">默认导出</Title>
        <p>
          每个模块都可以有一个default导出。 默认导出使用
          default关键字标记；并且一个模块只能够有一个default导出。 需要使用一种特殊的导入形式来导入
          default导出。
        </p>
        <p>
          default导出十分便利。 比如，像JQuery这样的类库可能有一个默认导出
          jQuery或$，并且我们基本上也会使用同样的名字jQuery或$导出JQuery。
        </p>
        <p>类和函数声明可以直接被标记为默认导出。 标记为默认导出的类和函数的名字是可以省略的。</p>
        <p>default导出也可以是一个值</p>
        <Title titleType="h2">export = 和 import = require()</Title>
        <p>CommonJS和AMD的环境里都有一个exports变量，这个变量包含了一个模块的所有导出内容。</p>
        <p>
          CommonJS和AMD的exports都可以被赋值为一个对象, 这种情况下其作用就类似于 es6
          语法里的默认导出，即 export default语法了。虽然作用相似，但是 export default
          语法并不能兼容CommonJS和AMD的exports。
        </p>
        <p>为了支持CommonJS和AMD的exports, TypeScript提供了export =语法。</p>
        <p>
          export =语法定义一个模块的导出对象。 这里的对象一词指的是类，接口，命名空间，函数或枚举。
        </p>
        <p>
          若使用export =导出一个模块，则必须使用TypeScript的特定语法import module =
          require("module")来导入此模块。
        </p>
        <Title titleType="h2">生成模块代码</Title>
        <p>
          根据编译时指定的模块目标参数，编译器会生成相应的供Node.js (CommonJS)，Require.js
          (AMD)，UMD，SystemJS或ECMAScript 2015 native modules (ES6)模块加载系统使用的代码。
          想要了解生成代码中 define，require 和 register的意义，请参考相应模块加载器的文档。
        </p>
        <Title titleType="h2">使用其它的JavaScript库</Title>
        <p>要想描述非TypeScript编写的类库的类型，我们需要声明类库所暴露出的API。</p>
        <p>
          我们叫它声明因为它不是“外部程序”的具体实现。 它们通常是在 .d.ts文件里定义的。
          如果你熟悉C/C++，你可以把它们当做 .h文件。 让我们看一些例子。
        </p>
        <Title titleType="h3">外部模块</Title>
        <p>
          在Node.js里大部分工作是通过加载一个或多个模块实现的。 我们可以使用顶级的
          export声明来为每个模块都定义一个.d.ts文件，但最好还是写在一个大的.d.ts文件里。
          我们使用与构造一个外部命名空间相似的方法，但是这里使用
          module关键字并且把名字用引号括起来，方便之后import。
        </p>
        <p>
          现在我们可以 node.d.ts并且使用import url = require("url");或import * as URL from
          "url"加载模块。
        </p>
        <Title titleType="h3">外部模块简写</Title>
        <p>
          假如你不想在使用一个新模块之前花时间去编写声明，你可以采用声明的简写形式以便能够快速使用它。
        </p>
        <p>declare module "hot-new-module";</p>
        <p>简写模块里所有导出的类型将是any。</p>
        <Title titleType="h3">模块声明通配符</Title>
        <p>
          某些模块加载器如SystemJS 和 AMD支持导入非JavaScript内容。
          它们通常会使用一个前缀或后缀来表示特殊的加载语法。 模块声明通配符可以用来表示这些情况。
        </p>
        <p>declare module "*!text"</p>
        <p>declare module "json!*"</p>
        <p>import fileContent from "./xyz.txt!text";</p>
        <p>import data from "json!http://example.com/data.json";</p>
        <Title titleType="h3">UMD模块</Title>
        <p>
          有些模块被设计成兼容多个模块加载器，或者不使用模块加载器（全局变量）。 它们以
          UMD模块为代表。 这些库可以通过导入的形式或全局变量的形式访问。
        </p>
        <Title titleType="h2">创建模块结构指导</Title>
        <Title titleType="h3">尽可能地在顶层导出</Title>
        <p>
          用户应该更容易地使用你模块导出的内容。
          嵌套层次过多会变得难以处理，因此仔细考虑一下如何组织你的代码。
        </p>
        <p>
          从你的模块中导出一个命名空间就是一个增加嵌套的例子。
          虽然命名空间有时候有它们的用处，在使用模块的时候它们额外地增加了一层。
          这对用户来说是很不便的并且通常是多余的。
        </p>
        <p>
          导出类的静态方法也有同样的问题 - 这个类本身就增加了一层嵌套。
          除非它能方便表述或便于清晰使用，否则请考虑直接导出一个辅助方法。
        </p>
        <p>
          <b>如果仅导出单个 class 或 function，使用 export default</b>
        </p>
        <p>
          就像“在顶层上导出”帮助减少用户使用的难度，一个默认的导出也能起到这个效果。
          如果一个模块就是为了导出特定的内容，那么你应该考虑使用一个默认导出。
          这会令模块的导入和使用变得些许简单。
        </p>
        <Title titleType="h3">如果要导出多个对象，把它们放在顶层里导出</Title>
        <p>
          相反地，当导入的时候：<b>明确地列出导入的名字</b>
        </p>
        <Title titleType="h3">模块里不要使用命名空间</Title>
        <p>
          当初次进入基于模块的开发模式时，可能总会控制不住要将导出包裹在一个命名空间里。
          模块具有其自己的作用域，并且只有导出的声明才会在模块外部可见。
          记住这点，命名空间在使用模块时几乎没什么价值。
        </p>
        <p>
          在组织方面，命名空间对于在全局作用域内对逻辑上相关的对象和类型进行分组是很便利的。
          例如，在C#里，你会从 System.Collections里找到所有集合的类型。
          通过将类型有层次地组织在命名空间里，可以方便用户找到与使用那些类型。
          然而，模块本身已经存在于文件系统之中，这是必须的。
          我们必须通过路径和文件名找到它们，这已经提供了一种逻辑上的组织形式。 我们可以创建
          /collections/generic/文件夹，把相应模块放在这里面。
        </p>
        <p>命名空间对解决全局作用域里命名冲突来说是很重要的。 </p>
        <Title titleType="h2">总结</Title>
        <p>文件的顶层声明是export namespace Foo ... （删除Foo并把所有内容向上层移动一层）</p>
        <p>文件只有一个export class或export function （考虑使用export default）</p>
        <p>多个文件的顶层具有同样的export namespace Foo （不要以为这些会合并到一个Foo中！）</p>
        <Title titleType="h1" id={titleList[13].nav}>
          {titleList[13].name}
        </Title>
        <p>
          关于术语的一点说明: 请务必注意一点，TypeScript 1.5里术语名已经发生了变化。
          “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”，这是为了与 ECMAScript
          2015里的术语保持一致，
        </p>
        <Title titleType="h2">介绍</Title>
        <p>
          这篇文章描述了如何在TypeScript里使用命名空间（之前叫做“内部模块”）来组织你的代码。
          就像我们在术语说明里提到的那样，“内部模块”现在叫做“命名空间”。 另外，任何使用
          module关键字来声明一个内部模块的地方都应该使用namespace关键字来替换。
          这就避免了让新的使用者被相似的名称所迷惑。
        </p>
        <Title titleType="h2">第一步</Title>
        <p>
          我们先来写一段程序并将在整篇文章中都使用这个例子。
          我们定义几个简单的字符串验证器，假设你会使用它们来验证表单里的用户输入或验证外部数据。
        </p>
        <Title titleType="h2">命名空间</Title>
        <p>
          随着更多验证器的加入，我们需要一种手段来组织代码，以便于在记录它们类型的同时还不用担心与其它对象产生命名冲突。
          因此，我们把验证器包裹到一个命名空间内，而不是把它们放在全局命名空间下。
        </p>
        <p>
          下面的例子里，把所有与验证器相关的类型都放到一个叫做Validation的命名空间里。
          因为我们想让这些接口和类在命名空间之外也是可访问的，所以需要使用 export。 相反的，变量
          lettersRegexp和numberRegexp是实现的细节，不需要导出，因此它们在命名空间外是不能访问的。
          在文件末尾的测试代码里，由于是在命名空间之外访问，因此需要限定类型的名称，比如
          Validation.LettersOnlyValidator。
        </p>
        <Title titleType="h2">分离到多文件</Title>
        <p>当应用变得越来越大时，我们需要将代码分离到不同的文件中以便于维护。</p>
        <Title titleType="h3">多文件中的命名空间</Title>
        <p>
          现在，我们把Validation命名空间分割成多个文件。
          尽管是不同的文件，它们仍是同一个命名空间，并且在使用的时候就如同它们在一个文件中定义的一样。
          因为不同文件之间存在依赖关系，所以我们加入了引用标签来告诉编译器文件之间的关联。
          我们的测试代码保持不变。
        </p>
        <p>当涉及到多文件时，我们必须确保所有编译后的代码都被加载了。 我们有两种方式。</p>
        <p>第一种方式，把所有的输入文件编译为一个输出文件，需要使用--outFile标记：</p>
        <p>tsc --outFile sample.js Test.ts</p>
        <p>编译器会根据源码里的引用标签自动地对输出进行排序。你也可以单独地指定每个文件。</p>
        <p>
          tsc --outFile sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts
        </p>
        <p>
          第二种方式，我们可以编译每一个文件（默认方式），那么每个源文件都会对应生成一个JavaScript文件。
          然后，在页面上通过 script标签把所有生成的JavaScript文件按正确的顺序引进来，
        </p>
        <Title titleType="h2">别名</Title>
        <p>
          另一种简化命名空间操作的方法是使用import q = x.y.z给常用的对象起一个短的名字。
          不要与用来加载模块的 import x =
          require('name')语法弄混了，这里的语法是为指定的符号创建一个别名。
          你可以用这种方法为任意标识符创建别名，也包括导入的模块中的对象。
        </p>
        <p>
          注意，我们并没有使用require关键字，而是直接使用导入符号的限定名赋值。 这与使用
          var相似，但它还适用于类型和导入的具有命名空间含义的符号。 重要的是，对于值来讲，
          import会生成与原始符号不同的引用，所以改变别名的var值并不会影响原始变量的值。
        </p>
        <Title titleType="h2">使用其它的JavaScript库</Title>
        <p>
          为了描述不是用TypeScript编写的类库的类型，我们需要声明类库导出的API。
          由于大部分程序库只提供少数的顶级对象，命名空间是用来表示它们的一个好办法。
        </p>
        <p>
          我们称其为声明是因为它不是外部程序的具体实现。 我们通常在 .d.ts里写这些声明。
          如果你熟悉C/C++，你可以把它们当做 .h文件。 让我们看一些例子。
        </p>
        <Title titleType="h3">外部命名空间</Title>
        <p>
          流行的程序库D3在全局对象d3里定义它的功能。 因为这个库通过一个
          script标签加载（不是通过模块加载器），它的声明文件使用内部模块来定义它的类型。
          为了让TypeScript编译器识别它的类型，我们使用外部命名空间声明。
        </p>
        <Title titleType="h1" id={titleList[14].nav}>
          {titleList[14].name}
        </Title>
        <Title titleType="h2">介绍</Title>
        <p>
          这篇文章将概括介绍在TypeScript里使用模块与命名空间来组织代码的方法。
          我们也会谈及命名空间和模块的高级使用场景，和在使用它们的过程中常见的陷阱。
        </p>
        <Title titleType="h2">使用命名空间</Title>
        <p>
          命名空间是位于全局命名空间下的一个普通的带有名字的JavaScript对象。
          这令命名空间十分容易使用。 它们可以在多文件中同时使用，并通过 --outFile结合在一起。
          命名空间是帮你组织Web应用不错的方式，你可以把所有依赖都放在HTML页面的 script标签里。
        </p>
        <p>
          但就像其它的全局命名空间污染一样，它很难去识别组件之间的依赖关系，尤其是在大型的应用中。
        </p>
        <Title titleType="h2">使用模块</Title>
        <p>像命名空间一样，模块可以包含代码和声明。 不同的是模块可以 声明它的依赖。</p>
        <p>
          模块会把依赖添加到模块加载器上（例如CommonJs / Require.js）。
          对于小型的JS应用来说可能没必要，但是对于大型应用，这一点点的花费会带来长久的模块化和可维护性上的便利。
          模块也提供了更好的代码重用，更强的封闭性以及更好的使用工具进行优化。
        </p>
        <p>对于Node.js应用来说，模块是默认并推荐的组织代码的方式。</p>
        <p>
          从ECMAScript 2015开始，模块成为了语言内置的部分，应该会被所有正常的解释引擎所支持。
          因此，对于新项目来说推荐使用模块做为组织代码的方式。
        </p>
        <Title titleType="h2">命名空间和模块的陷阱</Title>
        <p>这部分我们会描述常见的命名空间和模块的使用陷阱和如何去避免它们。</p>
        <Title titleType="h3">对模块使用/// reference</Title>
        <p>
          一个常见的错误是使用/// reference
          引用模块文件，应该使用import。要理解这之间的区别，我们首先应该弄清编译器是如何根据
          import路径（例如，import x from "...";或import x =
          require("...")里面的...，等等）来定位模块的类型信息的。
        </p>
        <p>
          编译器首先尝试去查找相应路径下的.ts，.tsx再或者.d.ts。 如果这些文件都找不到，编译器会查找
          外部模块声明。 回想一下，它们是在 .d.ts文件里声明的。
        </p>
        <p>这里的引用标签指定了外来模块的位置。 这就是一些TypeScript例子中引用 node.d.ts的方法。</p>
        <Title titleType="h3">不必要的命名空间</Title>
        <p>如果你想把命名空间转换为模块，它可能会像下面这个文件一样：</p>
        <p>顶层的模块Shapes包裹了Triangle和Square。 对于使用它的人来说这是令人迷惑和讨厌的：</p>
        <p>
          TypeScript里模块的一个特点是不同的模块永远也不会在相同的作用域内使用相同的名字。
          因为使用模块的人会为它们命名，所以完全没有必要把导出的符号包裹在一个命名空间里。
        </p>
        <p>
          <b>
            再次重申，不应该对模块使用命名空间，使用命名空间是为了提供逻辑分组和避免命名冲突。
            模块文件本身已经是一个逻辑分组，并且它的名字是由导入这个模块的代码指定，所以没有必要为导出的对象增加额外的模块层。
          </b>
        </p>
        <Title titleType="h3">模块的取舍</Title>
        <p>
          就像每个JS文件对应一个模块一样，TypeScript里模块文件与生成的JS文件也是一一对应的。
          这会产生一种影响，根据你指定的目标模块系统的不同，你可能无法连接多个模块源文件。
          例如当目标模块系统为 commonjs或umd时，无法使用outFile选项，但是在TypeScript
          1.8以上的版本能够使用outFile当目标为amd或system。
        </p>
        <Title titleType="h1" id={titleList[15].nav}>
          {titleList[15].name}
        </Title>
        <p>
          模块解析是指编译器在查找导入模块内容时所遵循的流程。假设有一个导入语句 import a from
          "moduleA"; 为了去检查任何对
          a的使用，编译器需要准确的知道它表示什么，并且需要检查它的定义moduleA。
        </p>
        <p>
          这时候，编译器会有个疑问“moduleA的结构是怎样的？” 这听上去很简单，但
          moduleA可能在你写的某个.ts/.tsx文件里或者在你的代码所依赖的.d.ts里。
        </p>
        <p>
          首先，编译器会尝试定位表示导入模块的文件。 编译器会遵循以下二种策略之一： Classic或Node。
          这些策略会告诉编译器到 哪里去查找moduleA。
        </p>
        <p>
          如果上面的解析失败了并且模块名是非相对的（且是在"moduleA"的情况下），编译器会尝试定位一个外部模块声明。
          我们接下来会讲到非相对导入。
        </p>
        <p>
          最后，如果编译器还是不能解析这个模块，它会记录一个错误。 在这种情况下，错误可能为 error
          TS2307: Cannot find module 'moduleA'.
        </p>
        <Title titleType="h3">相对 vs. 非相对模块导入</Title>
        <p>根据模块引用是相对的还是非相对的，模块导入会以不同的方式解析。</p>
        <p>相对导入是以/，./或../开头的。</p>
        <p>
          相对导入在解析时是相对于导入它的文件，并且不能解析为一个外部模块声明。
          你应该为你自己写的模块使用相对导入，这样能确保它们在运行时的相对位置。
        </p>
        <p>
          非相对模块的导入可以相对于baseUrl或通过下文会讲到的路径映射来进行解析。 它们还可以被解析成
          外部模块声明。 使用非相对路径来导入你的外部依赖。
        </p>
        <Title titleType="h3">模块解析策略</Title>
        <p>
          共有两种可用的模块解析策略：Node和Classic。 你可以使用
          --moduleResolution标记来指定使用哪种模块解析策略。若未指定，那么在使用了 --module AMD |
          System | ES2015时的默认值为Classic，其它情况时则为Node。
        </p>
        <Title titleType="h3">Classic</Title>
        <p>这种策略在以前是TypeScript默认的解析策略。 现在，它存在的理由主要是为了向后兼容。</p>
        <p>相对导入的模块是相对于导入它的文件进行解析的。</p>
        <p>
          对于非相对模块的导入，编译器则会从包含导入文件的目录开始依次向上级目录遍历，尝试定位匹配的声明文件。
        </p>
        <Title titleType="h3">Node</Title>
        <p>
          这个解析策略试图在运行时模仿Node.js模块解析机制。 完整的Node.js解析算法可以在 Node.js
          module documentation找到。
        </p>
        <p>Node.js如何解析模块</p>
        <p>
          为了理解TypeScript编译依照的解析步骤，先弄明白Node.js模块是非常重要的。
          通常，在Node.js里导入是通过 require函数调用进行的。 Node.js会根据
          require的是相对路径还是非相对路径做出不同的行为。
        </p>
        <p>相对路径：</p>
        <p>1. 检查/root/src/moduleB.js文件是否存在。</p>
        <p>2. 检查/root/src/moduleB目录是否包含一个package.json文件，且package.json文件指定了一个"main"模块。 在我们的例子里，如果Node.js发现文件 /root/src/moduleB/package.json包含了 "main": "lib/mainModule.js" ，那么Node.js会引用/root/src/moduleB/lib/mainModule.js。</p>
        <p>3. 检查/root/src/moduleB目录是否包含一个index.js文件。 这个文件会被隐式地当作那个文件夹下的"main"模块。</p>
        <p>非相对模块名的解析是个完全不同的过程:</p>
        <p>假设/root/src/moduleA.js里使用的是非相对路径导入var x = require("moduleB");。 Node则会以下面的顺序去解析 moduleB，直到有一个匹配上。</p>
        <p>1. /root/src/node_modules/moduleB.js</p>
        <p>2. /root/src/node_modules/moduleB/package.json (如果指定了"main"属性)</p>
        <p>3. /root/src/node_modules/moduleB/index.js</p>
        <p>4. /root/node_modules/moduleB.js</p>
        <p>5. /root/node_modules/moduleB/package.json</p>
        <p>6. /root/node_modules/moduleB/index.js</p>
        <p>7. /node_modules/moduleB.js</p>
        <p>8. /node_modules/moduleB/package.json</p>
        <p>9. /node_modules/moduleB/index.js</p>
        <Title titleType="h3">TypeScript如何解析模块</Title>
        <p>TypeScript是模仿Node.js运行时的解析策略来在编译阶段定位模块定义文件。 因此，TypeScript在Node解析逻辑基础上增加了TypeScript源文件的扩展名（ .ts，.tsx和.d.ts）。 同时，TypeScript在 package.json里使用字段"types"来表示类似"main"的意义 - 编译器会使用它来找到要使用的"main"定义文件。</p>
        <Title titleType="h3">附加的模块解析标记</Title>
        <p>有时工程源码结构与输出结构不同。 通常是要经过一系统的构建步骤最后生成输出。 它们包括将 .ts编译成.js，将不同位置的依赖拷贝至一个输出位置。 最终结果就是运行时的模块名与包含它们声明的源文件里的模块名不同。 或者最终输出文件里的模块路径与编译时的源文件路径不同了。</p>
        <p>TypeScript编译器有一些额外的标记用来通知编译器在源码编译成最终输出的过程中都发生了哪个转换。</p>
        <p>有一点要特别注意的是编译器不会进行这些转换操作； 它只是利用这些信息来指导模块的导入。</p>
        <p>Base URL: </p>
        <p>在利用AMD模块加载器的应用里使用baseUrl是常见做法，它要求在运行时模块都被放到了一个文件夹里。 这些模块的源码可以在不同的目录下，但是构建脚本会将它们集中到一起。</p>
        <p>设置baseUrl来告诉编译器到哪里去查找模块。 所有非相对模块导入都会被当做相对于 baseUrl。</p>
        <p>baseUrl的值由以下两者之一决定：</p>
        <p>命令行中baseUrl的值（如果给定的路径是相对的，那么将相对于当前路径进行计算）</p>
        <p>‘tsconfig.json’里的baseUrl属性（如果给定的路径是相对的，那么将相对于‘tsconfig.json’路径进行计算）</p>
        <p>注意相对模块的导入不会被设置的baseUrl所影响，因为它们总是相对于导入它们的文件。</p>
        <Title titleType="h3">路径映射</Title>
        <p>有时模块不是直接放在baseUrl下面。 比如，充分 "jquery"模块地导入，在运行时可能被解释为"node_modules/jquery/dist/jquery.slim.min.js"。 加载器使用映射配置来将模块名映射到运行时的文件</p>
        <p>TypeScript编译器通过使用tsconfig.json文件里的"paths"来支持这样的声明映射。</p>
        <p>请注意"paths"是相对于"baseUrl"进行解析。 如果 "baseUrl"被设置成了除"."外的其它值，比如tsconfig.json所在的目录，那么映射必须要做相应的改变。 如果你在上例中设置了 "baseUrl": "./src"，那么jquery应该映射到"../node_modules/jquery/dist/jquery"。</p>
        <p>通过"paths"我们还可以指定复杂的映射，包括指定多个回退位置。 假设在一个工程配置里，有一些模块位于一处，而其它的则在另个的位置。 构建过程会将它们集中至一处。</p>
        <Title titleType="h3">利用rootDirs指定虚拟目录</Title>
        <p>有时多个目录下的工程源文件在编译时会进行合并放在某个输出目录下。 这可以看做一些源目录创建了一个“虚拟”目录。</p>
        <Title titleType="h3">跟踪模块解析</Title>
        <p>如之前讨论，编译器在解析模块时可能访问当前文件夹外的文件。 这会导致很难诊断模块为什么没有被解析，或解析到了错误的位置。 通过 --traceResolution启用编译器的模块解析跟踪，它会告诉我们在模块解析过程中发生了什么。</p>
        <Title titleType="h3">为什么在exclude列表里的模块还会被编译器使用</Title>
        <p>tsconfig.json将文件夹转变一个“工程” 如果不指定任何 “exclude”或“files”，文件夹里的所有文件包括tsconfig.json和所有的子目录都会在编译列表里。 如果你想利用 “exclude”排除某些文件，甚至你想指定所有要编译的文件列表，请使用“files”。</p>
        <p>有些是被tsconfig.json自动加入的。 它不会涉及到上面讨论的模块解析。 如果编译器识别出一个文件是模块导入目标，它就会加到编译列表里，不管它是否被排除了。</p>
        <p>因此，要从编译列表中排除一个文件，你需要在排除它的同时，还要排除所有对它进行import或使用了/// reference path="..."指令的文件。</p>
        <Title titleType="h1" id={titleList[16].nav}>
          {titleList[16].name}
        </Title>
        <Title titleType="h2">介绍</Title>
        <p>TypeScript中有些独特的概念可以在类型层面上描述JavaScript对象的模型。 这其中尤其独特的一个例子是“声明合并”的概念。 理解了这个概念，将有助于操作现有的JavaScript代码。 同时，也会有助于理解更多高级抽象的概念。</p>
        <p>对本文件来讲，“声明合并”是指编译器将针对同一个名字的两个独立声明合并为单一声明。 合并后的声明同时拥有原先两个声明的特性。 任何数量的声明都可被合并；不局限于两个声明。</p>
        <Title titleType="h2">基础概念</Title>
        <p>TypeScript中的声明会创建以下三种实体之一：命名空间，类型或值。 创建命名空间的声明会新建一个命名空间，它包含了用（.）符号来访问时使用的名字。 创建类型的声明是：用声明的模型创建一个类型并绑定到给定的名字上。 最后，创建值的声明会创建在JavaScript输出中看到的值。</p>
        <Title titleType="h2">合并接口</Title>
        <p>最简单也最常见的声明合并类型是接口合并。 从根本上说，合并的机制是把双方的成员放到一个同名的接口里。</p>
        <Title titleType="h2">合并命名空间</Title>
        <p>与接口相似，同名的命名空间也会合并其成员。 命名空间会创建出命名空间和值，我们需要知道这两者都是怎么合并的。</p>
        <p>对于命名空间的合并，模块导出的同名接口进行合并，构成单一命名空间内含合并后的接口。</p>
        <p>对于命名空间里值的合并，如果当前已经存在给定名字的命名空间，那么后来的命名空间的导出成员会被加到已经存在的那个模块里。</p>
        <Title titleType="h2">命名空间与类和函数和枚举类型合并</Title>
        <p>命名空间可以与其它类型的声明进行合并。 只要命名空间的定义符合将要合并类型的定义。合并结果包含两者的声明类型。 TypeScript使用这个功能去实现一些JavaScript里的设计模式。</p>
        <Title titleType="h3">合并命名空间和类</Title>
        <Title titleType="h1" id={titleList[17].nav}>
          {titleList[17].name}
        </Title>
        <Title titleType="h2">介绍</Title>
        <p>JSX是一种嵌入式的类似XML的语法。 它可以被转换成合法的JavaScript，尽管转换的语义是依据不同的实现而定的。 JSX因React框架而流行，但也存在其它的实现。 TypeScript支持内嵌，类型检查以及将JSX直接编译为JavaScript。</p>
        <Title titleType="h2">基本用法</Title>
        <p>为了理解JSX的类型检查，你必须首先理解固有元素与基于值的元素之间的区别。 假设有这样一个JSX表达式expr，expr可能引用环境自带的某些东西（比如，在DOM环境里的div或span）或者是你自定义的组件。 这是非常重要的</p>
        <Title titleType="h1" id={titleList[19].nav}>
          {titleList[19].name}
        </Title>
        <p>三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用。</p>
        <p>三斜线指令仅可放在包含它的文件的最顶端。 一个三斜线指令的前面只能出现单行或多行注释，这包括其它的三斜线指令。 如果它们出现在一个语句或声明之后，那么它们会被当做普通的单行注释，并且不具有特殊的涵义。</p>
        <p>/// reference path="..." 指令是三斜线指令中最常见的一种。 它用于声明文件间的 依赖。</p>
        <p>三斜线引用告诉编译器在编译过程中要引入的额外的文件。</p>
        <p>reference types="..." </p>
        <p>与 reference path="..." 指令相似，这个指令是用来声明 依赖的</p>
        <p>仅当在你需要写一个d.ts文件时才使用这个指令。</p>
        <Title titleType="h1" id={titleList[20].nav}>
          {titleList[20].name}
        </Title>
        <p>你可以通过添加// @ts-nocheck注释来忽略类型检查；相反，你可以通过去掉--checkJs设置并添加一个// @ts-check注释来选则检查某些.js文件。 你还可以使用// @ts-ignore来忽略本行的错误。 如果你使用了tsconfig.json，JS检查将遵照一些严格检查标记，如noImplicitAny，strictNullChecks等。 但因为JS检查是相对宽松的，在使用严格标记时可能会有些出乎意料的情况。</p>
        <Title titleType="h2">支持的JSDoc</Title>
        <p>@type</p>
        <p>@param (or @arg or @argument)</p>
        <p>@returns (or @return)</p>
        <p>@typedef</p>
        <p>@callback</p>
        <p>@template</p>
        <p>@class (or @constructor)</p>
        <p>@this</p>
        <p>@extends (or @augments)</p>
        <p>@enum</p>
      </ContentLayout>
    </div>
  );
}
export default Home;
